#include "oop_context_menu_host.h"
#include <Windows.h>
#include <combaseapi.h>
#include "log.h"

using namespace std;
namespace PERF {
const CLSID CLSID_OOP_CONTEXTMENU_HOST = { 0xB75937F1, 0x6F3A, 0x411F,{0x9A, 0x13, 0x0A, 0x19, 0xE2, 0x5D, 0xF4, 0x14} };
OOPContextMenuHostAccelerator::OOPContextMenuHostAccelerator() {
	LOG_INFO("OOPContextMenuHostAccelerator::Constructor");
	hReleaseEvent_ = CreateEvent(
		NULL,               // default security attributes
		TRUE,               // manual-reset event
		FALSE,              // initial state is nonsignaled
		TEXT("Release OOP COM Object Event")  // object name
	);
}
OOPContextMenuHostAccelerator::~OOPContextMenuHostAccelerator() {
	Quit();
	if (hReleaseEvent_ != INVALID_HANDLE_VALUE) {
		CloseHandle(hReleaseEvent_);
	}
}
void OOPContextMenuHostAccelerator::Init() {
	LOG_INFO("OOPContextMenuHostAccelerator::Init");
	isRunning_ = false;
	if (hReleaseEvent_ != INVALID_HANDLE_VALUE) {
		ResetEvent(hReleaseEvent_);
		thread_ = std::thread(&OOPContextMenuHostAccelerator::Run, this);
	}
}
bool OOPContextMenuHostAccelerator::Run() {
	LOG_INFO("Run:begin");
	pmqi_ = { 0 };
	pmqi_.pIID = &IID_IUnknown;
	GUID oopGuid = { 0 };
	HRESULT hres = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
	if (hres != S_OK) {
		LOG_ERR("Run:Failed, unable to initialize");
		return false;
	}
	DWORD dwClsContext = CLSCTX_LOCAL_SERVER | CLSCTX_ACTIVATE_X86_SERVER;
	int tryTimes = 10;
	while (tryTimes > 0 && !isRunning_) {
		Sleep(1000);
		hres = CoCreateInstanceEx(
			CLSID_OOP_CONTEXTMENU_HOST,
			NULL,
			dwClsContext,
			NULL,
			1,
			&pmqi_
		);
		isRunning_ = (hres == S_OK);
		tryTimes--;
	}
	if (!isRunning_) {
		LOG_ERR("Run:Failed, unable to create");
		CoUninitialize();
		return false;
	}	
	CoLockObjectExternal(pmqi_.pItf, TRUE, FALSE);
	LOG_INFO("Run::success, waiting for release");
	DWORD dwWaitResult = WaitForSingleObject(hReleaseEvent_, INFINITE);
	if (dwWaitResult == WAIT_OBJECT_0) {
		Release_();
		LOG_INFO("Run::success, released");
	}
	CoUninitialize();
	return true;
}
void OOPContextMenuHostAccelerator::Quit() {
	if (hReleaseEvent_ != INVALID_HANDLE_VALUE) {
		LOG_INFO("Quit:begin");
		SetEvent(hReleaseEvent_);
		if (thread_.joinable()){
			thread_.join();
		}
		LOG_INFO("Quit:end");
	}
}
void OOPContextMenuHostAccelerator::Release_() {
	if (pmqi_.pItf != nullptr) {
		LOG_INFO("Release_::begin");
		CoLockObjectExternal(pmqi_.pItf, FALSE, FALSE);
		pmqi_.pItf->Release();
		isRunning_ = false;
		pmqi_.pItf = nullptr;
		LOG_INFO("Release_::end");
	}
}
}// endof namespace PERF
